package cn.blu10ph.trustshare.handler;

import cn.blu10ph.trustshare.bean.msg.TrustMsg;
import cn.blu10ph.trustshare.bean.node.TrustNode;
import cn.blu10ph.trustshare.constant.Constant;
import cn.blu10ph.trustshare.core.ServiceCore;
import cn.blu10ph.trustshare.service.DHTMsgService;
import cn.blu10ph.trustshare.util.ConvertUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.socket.DatagramPacket;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

/**
 * <p> DHTHandler </p >
 *
 * @author cxx
 * @date 2024/3/30 21:30
 */
@Slf4j
@Component
@ChannelHandler.Sharable
public class DHTHandler extends SimpleChannelInboundHandler<DatagramPacket> {

    @Resource
    ServiceCore serviceCore;

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) {
        byte[] buff = new byte[packet.content().readableBytes()];
        packet.content().readBytes(buff);
        ctx.executor().execute(() -> {
            String msg = new String(buff);
            log.info("receive channel id:{};msg:{}", ctx.channel().id(), msg);
            TrustMsg msgObj = null;
            try {
                msgObj = ConvertUtil.str2Obj(msg, TrustMsg.class);
            } catch (JsonProcessingException ex) {
                ex.printStackTrace();
                log.info("error msg id:{};msg:{}", ctx.channel().id(), msg);
                return;
            }

            // check msg sign
            boolean flg = serviceCore.checkMsgSign(msgObj);
            if(!flg) {
                log.info("msg check error id:{};msg:{}", ctx.channel().id(), msg);
                return;
            }

            String type = msgObj.getType();
            String direction = msgObj.getDirection();
            String nodeId = msgObj.getFrom();

            // set node active time
            serviceCore.setNodeActive(nodeId);

            // if not found this node, add this node.
            TrustNode fromNode = serviceCore.getNode(nodeId);
            if(ObjectUtils.isEmpty(fromNode) && !Constant.MSG_TYPE_GET_PUBLIC_KEY.equals(type)){
                log.info("get from node error:{}", nodeId);
                return;
            }

            DHTMsgService msgService = serviceCore.getMsgService(type);
            if(ObjectUtils.isEmpty(msgService)){
                log.info("error msg type id:{};msg:{}", ctx.channel().id(), msg);
                return;
            }
            if(Constant.MSG_DIRECTION_QUERY.equals(direction)){
                msgService.sendReturn(ctx, packet, fromNode, msgObj);
            } else {
                msgService.receive(ctx, packet, fromNode, msgObj);
            }

            // check_and_send_wait_msg
            serviceCore.checkAndSendWaitMsg(fromNode, msgObj);
        });
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        super.exceptionCaught(ctx, cause);
        cause.printStackTrace();
    }

}
